/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://gitee.com/newgolo/embedme.git
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __DEBUG_PRINT_H__
#define __DEBUG_PRINT_H__

#include "BaseType.h"
#include "Singleton.h"
#include "Thread.h"
#include "ThreadUtil.h"
#include "FileUtil.h"
#include "DateTime.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <iostream>
#include <typeinfo>

/**
 *  @file   Tracer.h   
 *  @brief  实现调试打印
 *  @note   打印等级高于当前等级的都能打印出来,如当前级别为1,则DBG(0)等级的信息不会被打印出来,大于等于当前等级的信息都能打印出来.默认为INFO(1)等级.
 */

#define BUILD_REL_VERSION			0	    /**< 打开后只打印ERR和REL级别的打印 */

//打印等级说明:只有大于或等于当前打印等级的消息才能被打印!

#define TRACE_LEVEL_DBG             0       /**< 用于调试信息的打印 */
#define TRACE_LEVEL_INFO            1       /**< 用于提示信息的打印 */
#define TRACE_LEVEL_WARN            2       /**< 用于警告信息打印 */
#define TRACE_LEVEL_ERR             3       /**< 用于错误信息的打印 */
#define TRACE_LEVEL_REL             4       /**< 用于用户信息的打印 */

/* linux标准错误字串 */
#define ERRSTR				(strerror(errno))
#define ERRMSG(err)			(strerror(err))

/* __VA_ARGS__宏是C99标准定义的 */
#define PRINTF(fmt,...)     do{printf(fmt,##__VA_ARGS__);}while(0)	


/* 颜色打印 */
#define TRACE_RED(fmt,arg...)       do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[31m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_GREEN(fmt,arg...)     do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[32m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_YELLOW(fmt,arg...)    do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[33m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_PINK(fmt,arg...)      do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[35m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_CYAN(fmt,arg...)      do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,"\033[36m\033[1m" fmt "\033[0m",##arg);}while(0)
/* 下面宏实现可以根据信息类型分颜色打印 */
#define TRACE_D(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_DBG,"\033[36m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_R(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_REL,fmt,##arg);}while(0)
#define TRACE_E(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_ERR,"\033[31m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_W(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_WARN,"\033[33m\033[1m" fmt "\033[0m",##arg);}while(0)
#define TRACE_I(fmt,arg...)         do{libemb::Tracer::getInstance().print(TRACE_LEVEL_INFO,"\033[32m\033[1m" fmt "\033[0m",##arg);}while(0)

/* 打印16进制字串 */
#define TRACE_HEX(tag,buf,len)      do{libemb::Tracer::getInstance().printHex(TRACE_LEVEL_DBG, tag, buf, len);}while(0)
#define TRACE_TEXT(fmt,arg...)      do{if(libemb::Tracer::getInstance().getLevel()==TRACE_LEVEL_DBG){\
                                       TRACE_CYAN("----------------------------------------\n");\
                                       printf(fmt,arg);\
                                       TRACE_CYAN("\n----------------------------------------\n");\
                                    }}while(0)

/* 按消息级别打印 */
#define TRACE_DBG(fmt,arg...)       {TRACE_D("[%s]<D@%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),__FUNCTION__,__LINE__,##arg);}   /**<调试信息打印 */
#define TRACE_INFO(fmt,arg...)      {TRACE_I("[%s]<I@%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),__FUNCTION__,__LINE__,##arg);}  /**<提示信息打印 */
#define TRACE_WARN(fmt,arg...)      {TRACE_W("[%s]<W@%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),__FUNCTION__,__LINE__,##arg);}  /**<警告信息打印 */
#define TRACE_ERR(fmt,arg...)       {TRACE_E("[%s]<E@%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),__FUNCTION__,__LINE__,##arg);}  /**<错误信息打印 */
#define TRACE_REL(fmt,arg...)       {TRACE_R("[%s]<R@%s>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),__FUNCTION__,##arg);}  /**<用户信息打印 */


/* 带类名的级别打印(仅在C++类中可使用,需要this指针) */
#define CLASS_NAME(classPtr)         (&(typeid(*classPtr).name()[1]))
#define TRACE_DBG_CLASS(fmt,arg...)     {TRACE_D("[%s]<D@%s::%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),this->className(),__FUNCTION__,__LINE__,##arg);}  /**<调试信息打印(带类名) */
#define TRACE_INFO_CLASS(fmt,arg...)    {TRACE_I("[%s]<I@%s::%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),this->className(),__FUNCTION__,__LINE__,##arg);}  /**<提示信息打印(带类名) */
#define TRACE_WARN_CLASS(fmt,arg...)    {TRACE_W("[%s]<W@%s::%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),this->className(),__FUNCTION__,__LINE__,##arg);}    /**<警告信息打印(带类名) */
#define TRACE_ERR_CLASS(fmt,arg...)     {TRACE_E("[%s]<E@%s::%s,L%d>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),this->className(),__FUNCTION__,__LINE__,##arg);}    /**<错误信息打印(带类名) */
#define TRACE_REL_CLASS(fmt,arg...)     {TRACE_R("[%s]<R@%s::%s>:" fmt,CSTR(libemb::DateTime::currentDateTime().toString()),this->className(),__FUNCTION__,##arg);}  /**<用户信息打印(带类名) */

/* 下面的宏用于调试跟踪 */
#define TRACE_IF(condition)         do{if((condition)){TRACE_RED("if(%s)<@%s,L%d>\n",#condition,__FUNCTION__,__LINE__);};}while(0)
#define TRACE_IF_CLASS(condition)   do{if((condition)){TRACE_RED("if(%s)<@%s::%s,L%d>\n",#condition,this->className(),__FUNCTION__,__LINE__);};}while(0)
#define TRACE_NONE(fmt,arg...)

#define TRACE_ASSERT(condition)  (if(!(condition)){TRACE_ERR("Assert !!!\n");while(1){libemb::Thread::msleep(100);}})

#if BUILD_REL_VERSION
#include "TracerLess.h"
#endif

namespace libemb{
using TracerCmder = std::function<void(const char*)>;	    /**< 远程命令函数对象:void func(const char* command) */
using TracerDumper = std::function<void(const char*,int)>;  /**< 日志打印函数对象:void func(const char* buf, int size) */
/**
 *  @class  Tracer
 *  @brief  调试跟踪类
 *  @note   用于程序调试
 */
class Tracer:public Singleton<Tracer>{
DECL_CLASSNAME(Tracer)
DECL_SINGLETON(Tracer)
public:
    ~Tracer();
    /**
     *  @brief  调试信息打印
     *  @param  level 打印级别
     *  @param  format 格式化字串
     *  @return void
     */
    void print(int level,const char* format,...);
    /**
     *  @brief  设置打印级别
     *  @param  level 打印级别
     *  @return void
     *  @note   默认打印级别为TRACE_LEVEL_INFO(不打印DBG信息)
     */
    void setLevel(int level);
    /**
     *  @brief  获取打印级别
     *  @param  void
     *  @return int 当前打印级别
     */
    int getLevel();
    /**
     *  @brief  以16进制字串的格式打印数据
     *  @param  level 打印级别
     *  @param  tag 标识字串
     *  @param  buf 要打印的内存块地址
     *  @param  len 要打印的内存块长度
     *  @return void
     */
    void printHex(int level,const char* tag,const char* buf,int len);
    /**
     * @brief 日志记录重定向
     * @param dumper 重定向函数对象
     * @note 可以将日志重定向到文件或其他输出设备
     */
	void setDumper(TracerDumper dumper);/* 设置记录函数,可以将Tracer信息记录到其他地方 */
    /**
     * @brief 设置远程命令
     * @param remoteMsg 远程消息
     * @param len 消息长度
     * @param cmder 远程命令对象
     * @return true 成功
     * @return false 失败
     */
	bool ttyRemote(const char* remoteMsg, int len,TracerCmder cmder=nullptr);
private:
	static const int TRACE_MAXLEN =4096;/* 打印长度最大为4096Bytes,超出后显示省略号 */
	std::unique_ptr<char[]> m_printBuf;
	TracerDumper m_dumper{nullptr};
    int m_traceLevel{TRACE_LEVEL_INFO};
	int m_remoteLevel{TRACE_LEVEL_REL};
	
};
}
#endif



